package com.remoter.basic.util;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Enumeration;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

/**
 * @author			koko
 * @date 			2017-08-08 13:07:14
 * @description 	类功能说明
 */
public class NetUtil {
	
	private static volatile InetAddress LOCAL_ADDRESS = null;
	
	public static final String LOCALHOST = "127.0.0.1";
    public static final String ANYHOST = "0.0.0.0";
    public static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$");
    public static final Pattern ADDRESS_PATTERN = Pattern.compile("^\\d{1,3}(\\.\\d{1,3}){3}\\:\\d{1,5}$");
    
    /**
     * 地址是否可用
     * @param address
     * @return
     */
    public static boolean isValidAddress(String address){
    	return ADDRESS_PATTERN.matcher(address).matches();
    }
    
    /**
     * 地址格式是否正确
     * @param address
     * @return
     */
	public static boolean isValidAddress(InetAddress address){
		if(null == address || address.isLoopbackAddress()){
			return false;
		}
		String name = address.getHostAddress();
		return (name != null && !ANYHOST.equals(name) && !LOCALHOST.equals(name) && IP_PATTERN.matcher(name).matches());
	}
	
	/**
	 * 获取InetAddress
	 * @return
	 */
	public static InetAddress getLocalAddressByHostName(){
		try{
			InetAddress localAddress = InetAddress.getLocalHost();
			if(isValidAddress(localAddress)){
				return localAddress;
			}
		}catch(Throwable e){}
		return null;
	}
	
	/**
	 * 获取InetAddress
	 * @return
	 */
	public static InetAddress getLocalAddressBySocket(Map<String, Integer> destHostPorts){
		if(destHostPorts == null || destHostPorts.size() == 0){
			return null;
		}
		for(Entry<String, Integer> entry : destHostPorts.entrySet()){
			String host = entry.getKey();
			int port = entry.getValue();
			try{
				Socket socket = new Socket();
				try{
					SocketAddress addr = new InetSocketAddress(host,port);
					socket.connect(addr,1000);
					return socket.getLocalAddress();
				}finally{
					socket.close();
				}
			}catch(Throwable e){}
		}
		return null;
	}
	
	/**
	 * 获取InetAddress
	 * @return
	 */
	public static InetAddress getLocalAddressByNetworkInterface(){
		try{
			Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
			if(null != interfaces){
				while(interfaces.hasMoreElements()){
					try{
						NetworkInterface network = interfaces.nextElement();
                        Enumeration<InetAddress> addresses = network.getInetAddresses();
                        while(addresses.hasMoreElements()){
                        	try{
                        		InetAddress address = addresses.nextElement();
                        		if(isValidAddress(address)){
                        			return address;
                        		}
                        	}catch(Throwable e){}
                        }
					}catch(Throwable e){}
				}
			}
		}catch(Throwable e){}
		return null;
	}
	
	/**
	 * 获取InetAddress
	 * @return
	 */
	public static InetAddress getLocalAddress(Map<String,Integer> destHostPorts){
		if(LOCAL_ADDRESS != null){
			return LOCAL_ADDRESS;
		}
		InetAddress localAddress = getLocalAddressByHostName();
		if(!isValidAddress(localAddress)){
			localAddress = getLocalAddressBySocket(destHostPorts);
		}
		if(!isValidAddress(localAddress)){
			localAddress = getLocalAddressByNetworkInterface();
		}
		if(isValidAddress(localAddress)){
			LOCAL_ADDRESS = localAddress;
		}
		return localAddress;
	}
	
	/**
	 * 获取InetAddress
	 * @return
	 */
	public static InetAddress getLocalAddress(){
		return getLocalAddress(null);
	}
	
	/**
	 * 获取随机可用端口
	 * @return
	 */
	public static int getAvailablePort(){
		try(ServerSocket serverSocket = new ServerSocket(0)){
			return serverSocket.getLocalPort();
		}catch(Exception e){
			return 0;
		}
	}
	
	/**
	 * IP地址格式转换为long类型
	 * @param ip
	 * @return
	 */
	public static long getIpToLong(String ip){
		ip = ip.trim();
		String[] ips = ip.split("\\.");
		long value = 0L;
		for(int i=0;i<ips.length;++i){
			value = value << 8 | Integer.parseInt(ips[i]);
		}
		return value;
	}
	
	public static boolean ipInRange(String ip,String section){
		if(StringUtil.isBlank(ip) || StringUtil.isBlank(section)){
			return false;
		}
		ip = ip.trim();
		section = section.trim();
		int idx = section.indexOf('-');
		if(idx < 0){
			return section.equals(ip);
		}
		String beginIP = section.substring(0,idx);
		String endIP = section.substring(idx + 1);
		return getIpToLong(beginIP) <= getIpToLong(ip) && getIpToLong(ip) <= getIpToLong(endIP);
	}
	
	public static String getHost(InetSocketAddress address){
		return address.getHostString();
	}
	public static int getPort(InetSocketAddress address){
		return address.getPort();
	}
	
}